#include "udsCommon.h"

#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <thread>
#include <chrono>
#include <sys/un.h>
#include <sys/inotify.h>
#include <arpa/inet.h>
#include <errno.h>

/**
 * @brief 设置未非阻塞模式
 * 
 * @param sock 
 */
void udsCommon::setNoBlocking(int sock)
{
	int opts;
	opts = fcntl(sock, F_GETFL);
	if (opts < 0) {
		perror("fcntl(sock,GETFL)");
	}
	opts = opts | O_NONBLOCK;
	if (fcntl(sock, F_SETFL, opts) < 0) {
		perror("fcntl(sock,SETFL,opts)");
	}
}

int udsCommon::createListenUds(const char *path)
{
	int lfd = 0;

	unlink(path);
	struct sockaddr_un serv_addr;
	lfd = socket(AF_UNIX, SOCK_STREAM, 0);
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sun_family = AF_UNIX;
	strcpy(serv_addr.sun_path, path);

	if ( lfd < 0 )
		return -errno;

	int ret = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	if ( ret != 0 ) 
		return -errno;

    ret = listen(lfd, 10);
    if ( ret != 0 ) 
		return -errno;

	return lfd;
}

int udsCommon::createListenTcp(const int port)
{
	int lfd = 0;

	struct sockaddr_in serv_addr;

	serv_addr.sin_family = AF_INET; // IP V4
	serv_addr.sin_port = htons(port); // 端口
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY 表示根据本机自动分配IP 地址

	lfd = socket(AF_INET, SOCK_STREAM, 0); // IP  流式套接子   0表示根据第2个参数推断tcp
	if ( lfd < 0 )
		return -errno;

    const int on=1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on,sizeof(on));

	int ret = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	if ( ret != 0 ) 
		return -errno;
	

    ret = listen(lfd, 10);
    if ( ret != 0 ) 
		return -errno;

	return lfd;
}

int udsCommon::listenAccpet(int fd)
{
    struct sockaddr_in caddr;
    memset(&caddr, 0, sizeof(caddr));
    socklen_t len = sizeof(caddr);

    int tmpfd = accept(fd, (struct sockaddr *)&caddr, &len);
    if ( tmpfd > 0 )
    {
       	setNoBlocking(tmpfd);

	    int send_buf_len = 128 * 1024; //实际缓冲区大小的一半。
		int len = sizeof(send_buf_len);
		if( setsockopt(tmpfd, SOL_SOCKET, SO_SNDBUF, (void *)&send_buf_len, len ) < 0 )
		{
			return -1;
		}

		if( setsockopt(tmpfd, SOL_SOCKET, SO_RCVBUF, (void *)&send_buf_len, len ) < 0 )
		{
			return -1;
		}

    }
    return tmpfd;
}

int udsCommon::tryGetConnectedTcpFd(int &socketfd, const char *ipaddr, int port)
{
	if (socketfd <= 0) {
		socketfd = socket(AF_INET, SOCK_STREAM, 0);

		struct sockaddr_in serv_addr;
		serv_addr.sin_family = AF_INET; // IP V4
		serv_addr.sin_port = htons(port); // 端口
		serv_addr.sin_addr.s_addr = inet_addr(ipaddr);

		int ret = connect(socketfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

		if (ret != 0) {
			close(socketfd);
			socketfd = -1;
		} else {
			setNoBlocking(socketfd);
		}
	}
	return socketfd;
}

int udsCommon::tryGetConnectedUdsFd(int &socketfd, const char *paths)
{
	if (socketfd <= 0) {
		socketfd = socket(AF_UNIX, SOCK_STREAM, 0);

		struct sockaddr_un serv_addr;
		memset(&serv_addr, 0, sizeof(serv_addr));

		serv_addr.sun_family = AF_UNIX; //uds
		strcpy(serv_addr.sun_path, paths);

		int ret = connect(socketfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));

		if (ret != 0) {
			close(socketfd);
			socketfd = -1;
		} else {
			setNoBlocking(socketfd);
		}
	}
	return socketfd;
}

int udsCommon::getDatas(int socketfd, unsigned char *buff, int maxlen, int timout)
{
	pollfd ipollfd;
	ipollfd.fd = socketfd;
	ipollfd.events = POLLIN;
	ipollfd.revents = 0;

	
	int frame_len = 0;
	int errorCount = 0;
	int readCount  = 0;
	while (frame_len < maxlen) {
		
		int pollret = poll(&ipollfd, 1, timout);
		if (pollret <= 0) {
			return -errno;
		}

		int ret = read(socketfd, buff + frame_len, maxlen - frame_len);
		// printf("[sunchao] udsCommon::getDatas ret:[%d] needRead:[%d] count:[%d]\n",ret ,(maxlen - frame_len) ,readCount++);
		if (ret > 0) {
			frame_len += ret;
		} 
		else if (errno == EAGAIN) 
		{
			// printf("[sunchao] udsCommon::getDatas error:[EAGAIN] \n");
			if (errorCount++ > 1000)
			{
				return  -errno;
			}
			usleep(5*1000);
			continue;
		} 
		else 
		{
			// printf("[sunchao] udsCommon::getDatas error:[%d] \n", errno);
			if (frame_len > 0) {
				return frame_len;
			}
			return -errno;
		}
	}
	if (frame_len > 0) {
		return frame_len;
	}
	return -errno;
}

int udsCommon::getUdsPacks(p_UdsHandler pHandler, int timout)
{
	int offSet = 0;
	int recvLen = 0;
	int recvHeadLen = getDatas(pHandler->fd, (unsigned char *)pHandler->pHead, pHandler->headLen, timout);
	if (recvHeadLen != pHandler->headLen)
		return  -1;

	p_UdsHead phead = (p_UdsHead)pHandler->pHead;
	int needReadDataLen = 0;
	for( size_t i = 0; i < phead->packCount && i < MAX_PACKS_NUM; i++)
	{
		needReadDataLen += phead->size[i];
	}
    if (!udsCommon::mallocHandler(pHandler, needReadDataLen)) {
        return -1;
    }
	
	if (	phead->mark[0] == 0xaa 
		&&	phead->mark[1] == 0xbb 
		&&	phead->mark[2] == 0xcc 
		&&	phead->mark[3] == 0xdd 
		&&	phead->packCount > 0
		)
	{
		for( size_t i = 0; i < phead->packCount && i < MAX_PACKS_NUM; i++)
		{
			if ( offSet + phead->size[i] > pHandler->maxMsgLen )
			{
				return -2;
			}

			if (phead->size[i] == 0)
			{
				continue;
			}

			int tmpRecvLen = 0;
			int tmpCount = 0;
			// int tmpReadCount = 0;
			do{
				int getLen = getDatas(pHandler->fd, (unsigned char *)pHandler->pMsg + offSet, phead->size[i] - tmpRecvLen, timout);
				// printf("[sunchao] getLen:[%d]  needReadLen[%d] count:[%d]\n", getLen, (phead->size[i] - tmpRecvLen), tmpReadCount++);
				if ( getLen > 0 )
				{
					tmpRecvLen += getLen;
				}	
				else
				{
					return -3;
				}
				
				if ( tmpRecvLen != phead->size[i]  )
				{
					usleep(10*1000);
					if (tmpCount++ > 1000)
					{
						return -4;
					}
				}
			}while(tmpRecvLen < phead->size[i]);

			pHandler->packsAddr[i] = pHandler->pMsg + offSet;
			pHandler->packsSize[i] = phead->size[i];
			offSet += tmpRecvLen;
		}
		pHandler->packsCount = phead->packCount;
		pHandler->cmd = phead->cmd;
		pHandler->msgLen = offSet;
		recvLen = offSet;
	}
	return  recvLen;
}

unsigned int udsCommon::crc_make(unsigned char *ptr, int len, unsigned int firstcrc)
{
	unsigned int crc = firstcrc;
	unsigned char i;
	while (len != 0) {
		if (len < 0)
			len = 0;
		crc ^= *ptr;
		for (i = 0; i < 8; i++) {
			if ((crc & 0x0001) == 0)
				crc = crc >> 1;
			else {
				crc = crc >> 1;
				crc ^= 0xa001;
			}
		}
		len -= 1;
		ptr++;
	}
	return crc;
}

std::unique_ptr<UdsPack> udsCommon::makeSendPack(int cmd, void **addr, size_t *size, int pack_count)
{
	std::unique_ptr<UdsPack> ret(new UdsPack);

	auto &bufvec = ret->bufvec;
	bufvec.resize(1);

	ret->head.mark[0] = 0xaa;
	ret->head.mark[1] = 0xbb;
	ret->head.mark[2] = 0xcc;
	ret->head.mark[3] = 0xdd;
	ret->head.cmd = cmd;
	ret->head.packCount = pack_count;

	//填充数据
	for (int i = 0; i < pack_count; i++) {
		ret->head.size[i] = size[i];
		iovec tmpiovec;
		tmpiovec.iov_base = addr[i];
		tmpiovec.iov_len = size[i];

		bufvec.push_back(tmpiovec);

		// #define get_nal_offset_type(p, offset) (*((char *)p + offset) & 0x1f)
		// if ( pack_count > 1)
        // 	printf("[sunchao] makeSendPack:[%d][%d] \n", i, get_nal_offset_type(addr[i], 4));
	}

	bufvec[0].iov_base = &ret->head;
	bufvec[0].iov_len = sizeof(UdsHead);

	//head部分添加crc (目前未做校验)
	unsigned int calcrc = 1011;//udsCommon::crc_make((unsigned char *)&ret->head, sizeof(UdsHead) - 4, 0xffff);
	ret->head.crc = calcrc;

	ret->aimlen = 0;
	for (auto &p : bufvec) {
		ret->aimlen += p.iov_len;
	}

	return ret;
}

int udsCommon::sendPacks(int fd, int cmd, void **addr, size_t *size, int pack_count)
{
	int wrlen = 0;
	auto pack = udsCommon::makeSendPack(cmd, addr, size, pack_count);

	if (!pack) {
		printf("sendPacks pack null\n");
		return -1;
	}
	int send_count = 0;
	auto &bufvec = pack->bufvec;
	do {
		int offset = wrlen;
		std::vector<iovec> sendvec;
		for (auto &p : bufvec) {
			if (p.iov_len > offset) {
				iovec tmpio;
				tmpio.iov_base = (char *)p.iov_base + offset;
				tmpio.iov_len = p.iov_len - offset;
				sendvec.push_back(tmpio);
				offset = 0;
			} else {
				offset -= p.iov_len;
			}
		}
		
		int retlen = writev(fd, &sendvec[0], sendvec.size());
		if (retlen < 0) {
			if ( send_count++ > 1000 || errno == EPIPE || errno == EBADF)
			{
				printf("sendPacks writev error = %d \n", errno);
				return -errno;
			}

			if ( errno == EAGAIN)
			{
				usleep(500*1000);
			}

			usleep(1000);
			continue;
		}
		else
		{
			send_count = 0;
			wrlen += retlen;
		}

		if (wrlen < pack->aimlen) {
			usleep(10000);
			continue;
		} else {
			break;
		}
	} while (1);

	if (wrlen != pack->aimlen)
	{
		printf("sendPacks writev error wrlen != pack->aimlen  [%d][%d] \n",wrlen ,pack->aimlen);
	}

	return wrlen - sizeof(UdsHead);
}

int udsCommon::sendMsg(int fd, int cmd, void *msg, int msgLen)
{
	void *packAddr[MAX_PACKS_NUM] = { 0 };
	size_t packsize[MAX_PACKS_NUM] = { 0 };

    packAddr[0] = msg;
    packsize[0] = msgLen;
    return udsCommon::sendPacks(fd, cmd, packAddr, packsize, 1);
}

p_UdsHandler udsCommon::creatHandler()
{
    p_UdsHandler pHandler = new UdsHandler();
    if (!pHandler){
        printf("create uds handler failed\n");
        return NULL;
    }

	pHandler->headLen = sizeof(UdsHead);
	pHandler->pHead = (char *)malloc(pHandler->headLen);

    if (!pHandler->pHead) {
        printf("malloc uds handler phead failed\n");
        return NULL;
    }

	memset(pHandler->pHead, 0, pHandler->headLen);
	
	// pHandler->maxMsgLen = udsCommon::getBufClusterSize(sizeof(UdsHead));
    // pHandler->pMsg = (char *)malloc(pHandler->maxMsgLen);;
    // memset(pHandler->pMsg, 0, pHandler->maxMsgLen);
    
	pHandler->maxMsgLen = 0;
    pHandler->msgLen = 0;
	pHandler->pMsg = NULL;
    pHandler->fd = -1;
    pHandler->cmd = 0;
    for( size_t i = 0; i < MAX_PACKS_NUM ; i++ )
    {
        pHandler->packsAddr[i] = NULL;
        pHandler->packsSize[i] = 0;
    }
    pHandler->packsCount = 0;
    pHandler->isLongLink = false;
	pHandler->pObj = NULL;

    return pHandler;
}

void udsCommon::destroyHandler(p_UdsHandler pHandler)
{
    if (pHandler->pMsg != NULL)
    {
        free(pHandler->pMsg);
        pHandler->pMsg = NULL;
		pHandler->maxMsgLen = 0;
    	pHandler->msgLen = 0;
    }

	if (pHandler->fd != -1)
	{
		close(pHandler->fd);
		pHandler->fd = -1;
	}

	if (pHandler->pHead)
	{
		free(pHandler->pHead);
        pHandler->pHead = NULL;
		pHandler->headLen = 0; 
	}
   
    delete pHandler;
    pHandler = NULL;
}

size_t udsCommon::getBufClusterSize(size_t len)
{
    return 4096*((len/4096)+1);
}

bool udsCommon::mallocHandler(p_UdsHandler pHandler, size_t len)
{
	size_t mallocLen = udsCommon::getBufClusterSize(len);
	if (pHandler->pMsg == NULL && pHandler->maxMsgLen == 0)
	{
		pHandler->pMsg = (char *)malloc(mallocLen);
        if (!pHandler->pMsg) return false;
    	memset(pHandler->pMsg, 0, mallocLen);
		pHandler->maxMsgLen = mallocLen;
	}
	else if (pHandler->pMsg != NULL && pHandler->maxMsgLen < mallocLen)
	{
		pHandler->pMsg = (char *)realloc(pHandler->pMsg, mallocLen);
        if (!pHandler->pMsg) return false;
		memset(pHandler->pMsg + pHandler->maxMsgLen, 0, mallocLen - pHandler->maxMsgLen);
		pHandler->maxMsgLen = mallocLen;
	}

	return true;
}

